#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
优化的Word文档解析器
====================

功能特点：
1. 全面内容提取：段落+表格+图片+超链接
2. 健壮错误处理：文件验证+异常恢复
3. 灵活配置选项：可定制的处理策略
4. 高性能处理：内存优化+批处理
5. 企业级质量：日志+监控+测试

作者：AI Assistant
版本：1.0.0
更新：2024年
"""

import os
import re
import json
import logging
from typing import Dict, List, Optional, Tuple, Any, Union
from pathlib import Path
from dataclasses import dataclass, asdict
from datetime import datetime
import tempfile
import time

# 核心依赖
from docx import Document
from docx.shared import Inches
from docx.table import Table
from docx.text.paragraph import Paragraph
from docx.document import Document as DocumentType
from docx.oxml.table import CT_Tbl
from docx.oxml.text.paragraph import CT_P
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT

# 可选依赖检查
try:
    from PIL import Image
    PIL_AVAILABLE = True
except ImportError:
    PIL_AVAILABLE = False
    print("⚠️  PIL未安装，图片处理功能受限。安装命令: pip install Pillow")

try:
    import magic
    MAGIC_AVAILABLE = True
except ImportError:
    MAGIC_AVAILABLE = False
    print("⚠️  python-magic未安装，文件类型检测功能受限。安装命令: pip install python-magic")

try:
    import chardet
    CHARDET_AVAILABLE = True
except ImportError:
    CHARDET_AVAILABLE = False
    print("⚠️  chardet未安装，编码检测功能受限。安装命令: pip install chardet")

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)


@dataclass
class DocumentConfig:
    """
    文档解析配置类
    
    用于控制文档解析的各种选项，提供灵活的定制能力
    """
    # 内容提取选项
    extract_paragraphs: bool = True      # 提取段落内容
    extract_tables: bool = True          # 提取表格数据
    extract_images: bool = True          # 提取图片信息
    extract_headers: bool = True         # 提取页眉页脚
    extract_hyperlinks: bool = True      # 提取超链接
    
    # 文本处理选项
    clean_text: bool = True             # 清理文本（去除特殊字符）
    remove_empty_paragraphs: bool = True # 移除空段落
    preserve_formatting: bool = True     # 保留格式信息
    normalize_whitespace: bool = True    # 标准化空白字符
    
    # 性能选项
    max_image_size_mb: int = 10         # 最大图片大小限制(MB)
    batch_size: int = 100               # 批处理大小
    
    # 输出选项
    output_format: str = 'structured'    # 输出格式: 'text', 'structured', 'json'
    encoding: str = 'utf-8'             # 文本编码
    
    # 调试选项
    verbose: bool = False               # 详细日志输出
    collect_warnings: bool = True       # 收集警告信息


@dataclass
class DocumentElement:
    """
    文档元素数据类
    
    表示文档中的一个逻辑元素（段落、表格、图片等）
    """
    type: str                           # 元素类型: paragraph, table, image, header
    content: str                        # 文本内容
    metadata: Dict[str, Any]            # 元数据信息
    position: int                       # 在文档中的位置
    level: Optional[int] = None         # 标题层级（仅标题有效）
    style: Optional[str] = None         # 样式名称


@dataclass
class DocumentParseResult:
    """
    文档解析结果类
    
    包含解析后的所有信息，包括成功状态、内容、错误信息等
    """
    success: bool                       # 解析是否成功
    elements: List[DocumentElement]     # 文档元素列表
    metadata: Dict[str, Any]            # 文档级元数据
    errors: List[str]                   # 错误信息列表
    warnings: List[str]                 # 警告信息列表
    processing_time: float              # 处理耗时（秒）
    
    def to_text(self, separator: str = '\n') -> str:
        """
        转换为纯文本格式
        
        Args:
            separator: 元素间的分隔符
            
        Returns:
            纯文本内容
        """
        text_parts = []
        for element in self.elements:
            if element.content and element.content.strip():
                text_parts.append(element.content.strip())
        
        return separator.join(text_parts)
    
    def to_structured_dict(self) -> Dict[str, Any]:
        """
        转换为结构化字典
        
        Returns:
            结构化数据字典
        """
        return {
            'success': self.success,
            'metadata': self.metadata,
            'content': {
                'elements': [asdict(element) for element in self.elements],
                'statistics': self.get_statistics()
            },
            'processing_info': {
                'processing_time': self.processing_time,
                'errors': self.errors,
                'warnings': self.warnings
            }
        }
    
    def to_json(self, indent: int = 2) -> str:
        """
        转换为JSON格式
        
        Args:
            indent: JSON缩进空格数
            
        Returns:
            JSON字符串
        """
        return json.dumps(self.to_structured_dict(), ensure_ascii=False, indent=indent)
    
    def get_statistics(self) -> Dict[str, int]:
        """
        获取内容统计信息
        
        Returns:
            统计信息字典
        """
        stats = {}
        for element in self.elements:
            element_type = element.type
            stats[element_type] = stats.get(element_type, 0) + 1
        
        return stats
    
    def filter_elements(self, element_type: str) -> List[DocumentElement]:
        """
        过滤指定类型的元素
        
        Args:
            element_type: 元素类型
            
        Returns:
            过滤后的元素列表
        """
        return [element for element in self.elements if element.type == element_type]


class DocumentProcessor:
    """
    高级Word文档处理器
    
    提供企业级的Word文档解析功能，支持全面的内容提取、
    健壮的错误处理和灵活的配置选项。
    """
    
    def __init__(self, config: Optional[DocumentConfig] = None):
        """
        初始化文档处理器
        
        Args:
            config: 处理配置，如果为None则使用默认配置
        """
        self.config = config or DocumentConfig()
        self.errors = []
        self.warnings = []
        
        # 预编译正则表达式以提高性能
        self._compiled_patterns = {
            'whitespace': re.compile(r'\s+'),
            'control_chars': re.compile(r'[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]'),
            'zero_width': re.compile(r'[\u200b-\u200f\ufeff]'),
            'multiple_newlines': re.compile(r'\n{3,}'),
            'smart_quotes': re.compile(r'[""'']')
        }
        
        if self.config.verbose:
            logger.setLevel(logging.DEBUG)
    
    def validate_file(self, file_path: Union[str, Path]) -> Tuple[bool, str]:
        """
        验证文件是否有效且可处理
        
        Args:
            file_path: 文件路径
            
        Returns:
            (是否有效, 错误信息)
        """
        file_path = Path(file_path)
        
        # 1. 检查文件是否存在
        if not file_path.exists():
            return False, f"文件不存在: {file_path}"
        
        # 2. 检查文件大小
        file_size = file_path.stat().st_size
        if file_size == 0:
            return False, "文件为空"
        
        # 大文件警告
        file_size_mb = file_size / (1024 * 1024)
        if file_size_mb > 100:
            self.warnings.append(f"文件较大 ({file_size_mb:.1f}MB)，处理可能较慢")
        
        # 3. 检查文件扩展名
        if file_path.suffix.lower() not in ['.docx', '.doc']:
            return False, f"不支持的文件格式: {file_path.suffix}，仅支持 .docx 和 .doc"
        
        # 4. 使用python-magic检查MIME类型（如果可用）
        if MAGIC_AVAILABLE:
            try:
                mime = magic.from_file(str(file_path), mime=True)
                expected_mimes = [
                    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                    'application/msword'
                ]
                
                if not any(expected in mime for expected in ['officedocument', 'msword']):
                    return False, f"文件类型不匹配，检测到: {mime}"
                    
            except Exception as e:
                self.warnings.append(f"文件类型检测失败: {str(e)}")
        
        # 5. 尝试读取文件头部（简单验证）
        try:
            with open(file_path, 'rb') as f:
                header = f.read(8)
                # DOCX文件应该以ZIP文件签名开头
                if file_path.suffix.lower() == '.docx':
                    if not header.startswith(b'PK'):
                        return False, "DOCX文件格式损坏（缺少ZIP签名）"
        except Exception as e:
            return False, f"无法读取文件: {str(e)}"
        
        return True, ""
    
    def extract_paragraph_info(self, paragraph: Paragraph, position: int) -> Optional[DocumentElement]:
        """
        提取段落信息，包括文本内容、样式和格式
        
        Args:
            paragraph: 段落对象
            position: 段落在文档中的位置
            
        Returns:
            文档元素对象，如果段落为空且配置要求移除则返回None
        """
        # 获取原始文本
        text = paragraph.text
        
        # 如果是空段落且配置要求移除
        if not text.strip() and self.config.remove_empty_paragraphs:
            return None
        
        # 清理文本
        if self.config.clean_text:
            text = self._clean_text(text)
        
        # 获取样式信息
        style_name = paragraph.style.name if paragraph.style else "Normal"
        
        # 检测标题层级
        level = self._detect_heading_level(style_name)
        
        # 构建元数据
        metadata = {
            'style': style_name,
            'original_length': len(paragraph.text),
            'cleaned_length': len(text)
        }
        
        # 添加格式信息（如果配置要求）
        if self.config.preserve_formatting:
            try:
                metadata.update({
                    'alignment': str(paragraph.alignment) if paragraph.alignment else 'LEFT',
                    'line_spacing': getattr(paragraph.paragraph_format, 'line_spacing', None),
                    'space_before': getattr(paragraph.paragraph_format, 'space_before', None),
                    'space_after': getattr(paragraph.paragraph_format, 'space_after', None)
                })
            except Exception as e:
                if self.config.verbose:
                    logger.debug(f"获取段落格式信息失败: {str(e)}")
        
        # 提取超链接（如果配置要求）
        if self.config.extract_hyperlinks:
            hyperlinks = self._extract_hyperlinks_from_paragraph(paragraph)
            if hyperlinks:
                metadata['hyperlinks'] = hyperlinks
        
        return DocumentElement(
            type='paragraph',
            content=text,
            metadata=metadata,
            position=position,
            level=level,
            style=style_name
        )
    
    def extract_table_info(self, table: Table, position: int) -> DocumentElement:
        """
        提取表格信息，包括结构化数据和格式化文本表示
        
        Args:
            table: 表格对象
            position: 表格在文档中的位置
            
        Returns:
            表格文档元素
        """
        # 提取表格数据
        table_data = []
        for row_idx, row in enumerate(table.rows):
            row_data = []
            for cell_idx, cell in enumerate(row.cells):
                cell_text = cell.text.strip()
                if self.config.clean_text:
                    cell_text = self._clean_text(cell_text)
                row_data.append(cell_text)
            
            # 只添加非空行
            if any(cell.strip() for cell in row_data):
                table_data.append(row_data)
        
        # 检测表头
        has_header = self._detect_table_header(table_data)
        
        # 生成格式化文本
        formatted_text = self._format_table_text(table_data, has_header)
        
        # 构建元数据
        metadata = {
            'rows': len(table_data),
            'columns': len(table_data[0]) if table_data else 0,
            'has_header': has_header,
            'raw_data': table_data,
            'empty_cells': self._count_empty_cells(table_data)
        }
        
        return DocumentElement(
            type='table',
            content=formatted_text,
            metadata=metadata,
            position=position
        )
    
    def extract_image_info(self, doc: DocumentType) -> List[DocumentElement]:
        """
        提取文档中的图片信息
        
        Args:
            doc: 文档对象
            
        Returns:
            图片元素列表
        """
        if not self.config.extract_images:
            return []
        
        image_elements = []
        
        try:
            # 获取文档中的所有关联部分
            image_parts = doc.part.related_parts
            
            for rel_id, related_part in image_parts.items():
                if "image" in related_part.content_type:
                    try:
                        image_element = self._process_image_part(related_part, rel_id, len(image_elements))
                        if image_element:
                            image_elements.append(image_element)
                    except Exception as e:
                        self.warnings.append(f"处理图片 {rel_id} 时出错: {str(e)}")
                        
        except Exception as e:
            self.warnings.append(f"提取图片信息时出错: {str(e)}")
        
        return image_elements
    
    def _process_image_part(self, related_part, rel_id: str, position: int) -> Optional[DocumentElement]:
        """
        处理单个图片部分
        
        Args:
            related_part: 图片关联部分
            rel_id: 关系ID
            position: 位置
            
        Returns:
            图片元素或None
        """
        try:
            # 获取图片数据
            image_data = related_part.blob
            
            # 检查图片大小
            image_size_mb = len(image_data) / (1024 * 1024)
            if image_size_mb > self.config.max_image_size_mb:
                self.warnings.append(f"图片过大，跳过: {image_size_mb:.1f}MB")
                return None
            
            # 获取基本信息
            content_type = related_part.content_type
            image_format = content_type.split('/')[-1].upper()
            
            # 初始化元数据
            metadata = {
                'format': image_format,
                'size_bytes': len(image_data),
                'size_mb': round(image_size_mb, 2),
                'relation_id': rel_id,
                'content_type': content_type
            }
            
            # 如果PIL可用，获取详细图片信息
            if PIL_AVAILABLE:
                try:
                    with tempfile.NamedTemporaryFile() as tmp:
                        tmp.write(image_data)
                        tmp.flush()
                        
                        with Image.open(tmp.name) as img:
                            width, height = img.size
                            metadata.update({
                                'width': width,
                                'height': height,
                                'aspect_ratio': round(width / height, 2) if height > 0 else 0,
                                'mode': img.mode,
                                'has_transparency': img.mode in ('RGBA', 'LA') or 'transparency' in img.info
                            })
                            
                except Exception as e:
                    self.warnings.append(f"无法解析图片详细信息: {str(e)}")
            
            # 生成内容描述
            content_parts = [f"图片 ({image_format}"]
            content_parts.append(f"{image_size_mb:.1f}MB")
            
            if 'width' in metadata and 'height' in metadata:
                content_parts.append(f"{metadata['width']}×{metadata['height']}px")
            
            content = ", ".join(content_parts) + ")"
            
            return DocumentElement(
                type='image',
                content=content,
                metadata=metadata,
                position=position
            )
            
        except Exception as e:
            logger.debug(f"处理图片部分时出错: {str(e)}")
            return None
    
    def _clean_text(self, text: str) -> str:
        """
        清理文本内容，移除不需要的字符和格式
        
        Args:
            text: 原始文本
            
        Returns:
            清理后的文本
        """
        if not text:
            return ""
        
        # 使用预编译的正则表达式
        patterns = self._compiled_patterns
        
        # 移除控制字符
        text = patterns['control_chars'].sub('', text)
        
        # 移除零宽字符
        text = patterns['zero_width'].sub('', text)
        
        # 标准化空白字符
        if self.config.normalize_whitespace:
            text = patterns['whitespace'].sub(' ', text)
        
        # 标准化引号
        text = text.replace('"', '"').replace('"', '"')
        text = text.replace(''', "'").replace(''', "'")
        
        # 移除多余的换行符
        text = patterns['multiple_newlines'].sub('\n\n', text)
        
        return text.strip()
    
    def _detect_heading_level(self, style_name: str) -> Optional[int]:
        """
        检测标题层级
        
        Args:
            style_name: 样式名称
            
        Returns:
            标题层级，如果不是标题则返回None
        """
        if not style_name:
            return None
        
        # 检测各种标题格式
        heading_patterns = [
            (r'Heading\s*(\d+)', lambda m: int(m.group(1))),
            (r'标题\s*(\d+)', lambda m: int(m.group(1))),
            (r'Title', lambda m: 1),
            (r'Subtitle', lambda m: 2),
            (r'H(\d+)', lambda m: int(m.group(1)))
        ]
        
        for pattern, extractor in heading_patterns:
            match = re.search(pattern, style_name, re.IGNORECASE)
            if match:
                try:
                    return extractor(match)
                except (ValueError, AttributeError):
                    continue
        
        return None
    
    def _detect_table_header(self, table_data: List[List[str]]) -> bool:
        """
        检测表格是否有表头
        
        Args:
            table_data: 表格数据
            
        Returns:
            是否有表头
        """
        if not table_data or len(table_data) < 2:
            return False
        
        first_row = table_data[0]
        
        # 检查第一行是否全部非空
        if not all(cell.strip() for cell in first_row):
            return False
        
        # 检查第一行的内容是否看起来像标题
        # 简单启发式：如果第一行的内容都比较短且不包含数字，可能是表头
        for cell in first_row:
            if len(cell) > 50:  # 表头通常较短
                return False
            # 如果包含很多数字，可能不是表头
            digit_ratio = sum(c.isdigit() for c in cell) / len(cell) if cell else 0
            if digit_ratio > 0.5:
                return False
        
        return True
    
    def _format_table_text(self, table_data: List[List[str]], has_header: bool) -> str:
        """
        格式化表格为文本表示
        
        Args:
            table_data: 表格数据
            has_header: 是否有表头
            
        Returns:
            格式化的表格文本
        """
        if not table_data:
            return "空表格"
        
        lines = []
        
        # 添加表格描述
        rows_count = len(table_data)
        cols_count = len(table_data[0]) if table_data else 0
        lines.append(f"表格 ({rows_count}行 × {cols_count}列)")
        
        if has_header and table_data:
            # 有表头的情况
            headers = table_data[0]
            data_rows = table_data[1:]
            
            lines.append("表头: " + " | ".join(headers))
            lines.append("---")
            
            for i, row in enumerate(data_rows, 1):
                lines.append(f"第{i}行: " + " | ".join(row))
        else:
            # 无表头的情况
            for i, row in enumerate(table_data, 1):
                lines.append(f"第{i}行: " + " | ".join(row))
        
        return "\n".join(lines)
    
    def _count_empty_cells(self, table_data: List[List[str]]) -> int:
        """
        计算表格中空单元格的数量
        
        Args:
            table_data: 表格数据
            
        Returns:
            空单元格数量
        """
        empty_count = 0
        for row in table_data:
            for cell in row:
                if not cell.strip():
                    empty_count += 1
        return empty_count
    
    def _extract_hyperlinks_from_paragraph(self, paragraph: Paragraph) -> List[Dict[str, str]]:
        """
        从段落中提取超链接信息
        
        Args:
            paragraph: 段落对象
            
        Returns:
            超链接信息列表
        """
        hyperlinks = []
        
        try:
            # 遍历段落中的所有run
            for run in paragraph.runs:
                # 检查run是否包含超链接
                hyperlink_elements = run.element.xpath('.//w:hyperlink')
                for hl in hyperlink_elements:
                    link_text = ''.join(hl.itertext()).strip()
                    if link_text:
                        hyperlink_info = {
                            'text': link_text,
                            'type': 'hyperlink'
                        }
                        
                        # 尝试获取URL（需要访问关系部分）
                        try:
                            r_id = hl.get('{http://schemas.openxmlformats.org/officeDocument/2006/relationships}id')
                            if r_id:
                                hyperlink_info['relation_id'] = r_id
                        except Exception:
                            pass
                        
                        hyperlinks.append(hyperlink_info)
                        
        except Exception as e:
            if self.config.verbose:
                logger.debug(f"提取超链接时出错: {str(e)}")
        
        return hyperlinks
    
    def _extract_document_metadata(self, doc: DocumentType, file_path: Union[str, Path]) -> Dict[str, Any]:
        """
        提取文档元数据
        
        Args:
            doc: 文档对象
            file_path: 文件路径
            
        Returns:
            文档元数据字典
        """
        file_path = Path(file_path)
        
        # 基础文件信息
        metadata = {
            'file_name': file_path.name,
            'file_size_bytes': file_path.stat().st_size,
            'file_size_mb': round(file_path.stat().st_size / (1024 * 1024), 2),
            'file_modified': datetime.fromtimestamp(file_path.stat().st_mtime).isoformat(),
            'paragraph_count': len(doc.paragraphs),
            'table_count': len(doc.tables)
        }
        
        # 提取文档核心属性
        try:
            core_props = doc.core_properties
            
            if core_props.title:
                metadata['title'] = core_props.title
            if core_props.author:
                metadata['author'] = core_props.author
            if core_props.subject:
                metadata['subject'] = core_props.subject
            if core_props.keywords:
                metadata['keywords'] = core_props.keywords
            if core_props.comments:
                metadata['comments'] = core_props.comments
            if core_props.created:
                metadata['created'] = core_props.created.isoformat()
            if core_props.modified:
                metadata['modified'] = core_props.modified.isoformat()
            if core_props.last_modified_by:
                metadata['last_modified_by'] = core_props.last_modified_by
            if core_props.revision:
                metadata['revision'] = core_props.revision
                
        except Exception as e:
            self.warnings.append(f"无法提取文档属性: {str(e)}")
        
        return metadata
    
    def load_employee_file_optimized(self, file_path: Union[str, Path]) -> DocumentParseResult:
        """
        优化的员工手册文件加载函数
        
        这是核心处理函数，提供完整的文档解析功能
        
        Args:
            file_path: 文件路径
            
        Returns:
            文档解析结果
        """
        start_time = time.time()
        self.errors.clear()
        self.warnings.clear()
        
        if self.config.verbose:
            logger.info(f"开始处理文档: {file_path}")
        
        try:
            # 第一步：文件验证
            is_valid, error_msg = self.validate_file(file_path)
            if not is_valid:
                return DocumentParseResult(
                    success=False,
                    elements=[],
                    metadata={},
                    errors=[error_msg],
                    warnings=self.warnings,
                    processing_time=time.time() - start_time
                )
            
            # 第二步：加载文档
            try:
                doc = Document(file_path)
            except Exception as e:
                error_msg = f"无法加载文档: {str(e)}"
                return DocumentParseResult(
                    success=False,
                    elements=[],
                    metadata={},
                    errors=[error_msg],
                    warnings=self.warnings,
                    processing_time=time.time() - start_time
                )
            
            # 第三步：提取文档元数据
            doc_metadata = self._extract_document_metadata(doc, file_path)
            
            # 第四步：提取所有元素
            elements = []
            position = 0
            
            # 按文档顺序处理段落和表格
            if self.config.extract_paragraphs or self.config.extract_tables:
                for element in doc.element.body:
                    try:
                        if isinstance(element, CT_P) and self.config.extract_paragraphs:
                            # 处理段落
                            paragraph = Paragraph(element, doc)
                            para_element = self.extract_paragraph_info(paragraph, position)
                            if para_element:
                                elements.append(para_element)
                                position += 1
                                
                        elif isinstance(element, CT_Tbl) and self.config.extract_tables:
                            # 处理表格
                            table = Table(element, doc)
                            table_element = self.extract_table_info(table, position)
                            elements.append(table_element)
                            position += 1
                            
                    except Exception as e:
                        self.warnings.append(f"处理文档元素时出错: {str(e)}")
                        continue
            
            # 第五步：提取图片信息
            if self.config.extract_images:
                try:
                    image_elements = self.extract_image_info(doc)
                    elements.extend(image_elements)
                except Exception as e:
                    self.warnings.append(f"提取图片时出错: {str(e)}")
            
            # 第六步：计算处理时间
            processing_time = time.time() - start_time
            
            if self.config.verbose:
                logger.info(f"文档处理完成: {len(elements)}个元素, 耗时{processing_time:.2f}秒")
            
            return DocumentParseResult(
                success=True,
                elements=elements,
                metadata=doc_metadata,
                errors=self.errors.copy(),
                warnings=self.warnings.copy(),
                processing_time=processing_time
            )
            
        except Exception as e:
            error_msg = f"处理文档时发生未预期的错误: {str(e)}"
            logger.error(error_msg)
            
            return DocumentParseResult(
                success=False,
                elements=[],
                metadata={},
                errors=[error_msg],
                warnings=self.warnings,
                processing_time=time.time() - start_time
            )


# ================================
# 便利函数和公共接口
# ================================

def load_employee_file_enhanced(file_path: Union[str, Path], 
                               config: Optional[DocumentConfig] = None) -> DocumentParseResult:
    """
    增强版员工手册加载函数 - 主要公共接口
    
    Args:
        file_path: 文件路径
        config: 解析配置，None时使用默认配置
        
    Returns:
        解析结果对象
        
    Example:
        >>> result = load_employee_file_enhanced('manual.docx')
        >>> if result.success:
        ...     print(f"提取了 {len(result.elements)} 个元素")
        ...     text = result.to_text()
    """
    processor = DocumentProcessor(config)
    return processor.load_employee_file_optimized(file_path)


def load_employee_file_simple(file_path: Union[str, Path], 
                             clean_text: bool = True,
                             include_tables: bool = True) -> str:
    """
    简化版接口 - 直接返回文本内容
    
    Args:
        file_path: 文件路径
        clean_text: 是否清理文本
        include_tables: 是否包含表格内容
        
    Returns:
        文档文本内容
        
    Raises:
        Exception: 当文档解析失败时
        
    Example:
        >>> text = load_employee_file_simple('manual.docx')
        >>> print(f"文档长度: {len(text)} 字符")
    """
    config = DocumentConfig(
        clean_text=clean_text,
        extract_tables=include_tables,
        extract_images=False,  # 简化版不提取图片
        verbose=False
    )
    
    result = load_employee_file_enhanced(file_path, config)
    
    if result.success:
        return result.to_text()
    else:
        error_details = '; '.join(result.errors)
        raise Exception(f"文档解析失败: {error_details}")


def create_rag_friendly_chunks(file_path: Union[str, Path], 
                              chunk_size: int = 500,
                              preserve_structure: bool = True) -> List[str]:
    """
    为RAG系统创建友好的文档块
    
    Args:
        file_path: 文件路径
        chunk_size: 块大小（字符数）
        preserve_structure: 是否保持文档结构
        
    Returns:
        文档块列表
        
    Example:
        >>> chunks = create_rag_friendly_chunks('manual.docx')
        >>> print(f"生成了 {len(chunks)} 个文档块")
    """
    result = load_employee_file_enhanced(file_path)
    
    if not result.success:
        raise Exception(f"文档解析失败: {'; '.join(result.errors)}")
    
    chunks = []
    
    if preserve_structure:
        # 保持结构的切分方式
        current_section = ""
        current_heading = ""
        
        for element in result.elements:
            if element.level:  # 标题
                # 保存上一节内容
                if current_section.strip():
                    section_content = f"{current_heading}\n{current_section}".strip()
                    chunks.extend(_split_long_text(section_content, chunk_size))
                
                # 开始新节
                current_heading = element.content
                current_section = ""
                
            elif element.type in ['paragraph', 'table']:
                current_section += element.content + "\n"
        
        # 添加最后一节
        if current_section.strip():
            section_content = f"{current_heading}\n{current_section}".strip()
            chunks.extend(_split_long_text(section_content, chunk_size))
    
    else:
        # 简单的固定长度切分
        full_text = result.to_text()
        chunks = _split_long_text(full_text, chunk_size)
    
    return [chunk for chunk in chunks if chunk.strip()]


def _split_long_text(text: str, chunk_size: int) -> List[str]:
    """
    将长文本切分为指定大小的块
    
    Args:
        text: 待切分文本
        chunk_size: 块大小
        
    Returns:
        文本块列表
    """
    if len(text) <= chunk_size:
        return [text]
    
    chunks = []
    start = 0
    
    while start < len(text):
        end = start + chunk_size
        
        # 如果不是最后一块，尝试在句号处切分
        if end < len(text):
            # 寻找最近的句号
            for i in range(end, max(start + chunk_size // 2, end - 100), -1):
                if text[i] in '。！？\n':
                    end = i + 1
                    break
        
        chunk = text[start:end].strip()
        if chunk:
            chunks.append(chunk)
        
        start = end
    
    return chunks


# ================================
# 演示和测试函数
# ================================

def demo_usage():
    """演示优化后的文档处理功能"""
    
    print("🎯 Word文档解析优化演示")
    print("=" * 60)
    
    # 1. 基础使用演示
    print("\n1. 基础文档解析:")
    try:
        result = load_employee_file_enhanced('employee_manual.docx')
        
        if result.success:
            print(f"✅ 解析成功!")
            print(f"📄 提取元素: {len(result.elements)}个")
            print(f"⏱️ 处理时间: {result.processing_time:.2f}秒")
            
            # 显示统计信息
            stats = result.get_statistics()
            print("📊 元素统计:")
            for elem_type, count in stats.items():
                print(f"  - {elem_type}: {count}个")
            
            # 显示前几个元素
            print("\n📝 前3个元素预览:")
            for i, element in enumerate(result.elements[:3]):
                preview = element.content[:80] + "..." if len(element.content) > 80 else element.content
                print(f"  {i+1}. [{element.type}] {preview}")
                
        else:
            print(f"❌ 解析失败:")
            for error in result.errors:
                print(f"   - {error}")
            
    except Exception as e:
        print(f"❌ 处理出错: {str(e)}")
    
    # 2. 自定义配置演示
    print("\n2. 自定义配置解析:")
    custom_config = DocumentConfig(
        extract_tables=True,
        extract_images=True,
        clean_text=True,
        preserve_formatting=True,
        verbose=False
    )
    
    try:
        result = load_employee_file_enhanced('employee_manual.docx', custom_config)
        if result.success:
            print(f"✅ 自定义解析成功! 元素数: {len(result.elements)}")
            
            # 显示警告信息
            if result.warnings:
                print("⚠️  警告信息:")
                for warning in result.warnings:
                    print(f"   - {warning}")
                    
    except Exception as e:
        print(f"❌ 自定义配置处理出错: {str(e)}")
    
    # 3. 简化接口演示
    print("\n3. 简化接口使用:")
    try:
        text_content = load_employee_file_simple('employee_manual.docx')
        print(f"✅ 简化接口成功! 文本长度: {len(text_content)}字符")
        preview = text_content[:150] + "..." if len(text_content) > 150 else text_content
        print(f"📝 文本预览: {preview}")
    except Exception as e:
        print(f"❌ 简化接口处理出错: {str(e)}")
    
    # 4. RAG块生成演示
    print("\n4. RAG文档块生成:")
    try:
        chunks = create_rag_friendly_chunks('employee_manual.docx', chunk_size=300)
        print(f"✅ RAG块生成成功! 生成 {len(chunks)} 个块")
        
        if chunks:
            avg_length = sum(len(chunk) for chunk in chunks) / len(chunks)
            print(f"📊 平均块长度: {avg_length:.0f}字符")
            
            print("📝 第一个块预览:")
            preview = chunks[0][:100] + "..." if len(chunks[0]) > 100 else chunks[0]
            print(f"   {preview}")
            
    except Exception as e:
        print(f"❌ RAG块生成出错: {str(e)}")


def performance_comparison():
    """性能对比测试"""
    
    print("\n🔬 性能对比测试")
    print("=" * 60)
    
    # 原始实现
    def original_load_employee_file(file_path):
        from docx import Document
        document = Document(file_path)
        all_text = []
        for para in document.paragraphs:
            clean_text = para.text.strip()
            all_text.append(clean_text)
        return '\n'.join(all_text)
    
    # 测试文件
    test_file = 'employee_manual.docx'
    
    try:
        # 测试原始版本
        start_time = time.time()
        original_result = original_load_employee_file(test_file)
        original_time = time.time() - start_time
        
        # 测试优化版本
        start_time = time.time()
        optimized_result = load_employee_file_simple(test_file)
        optimized_time = time.time() - start_time
        
        # 显示对比结果
        print(f"原始版本:")
        print(f"  处理时间: {original_time:.4f}秒")
        print(f"  文本长度: {len(original_result)}字符")
        
        print(f"\n优化版本:")
        print(f"  处理时间: {optimized_time:.4f}秒")
        print(f"  文本长度: {len(optimized_result)}字符")
        
        # 性能提升计算
        if original_time > 0:
            speed_improvement = ((original_time - optimized_time) / original_time) * 100
            print(f"\n🚀 性能对比:")
            print(f"  速度变化: {speed_improvement:+.1f}%")
            print(f"  内容增加: {len(optimized_result) - len(original_result):+d}字符")
        
    except Exception as e:
        print(f"❌ 性能测试失败: {str(e)}")


if __name__ == "__main__":
    # 运行演示
    demo_usage()
    
    # 运行性能对比
    performance_comparison()
    
    print("\n" + "="*60)
    print("🎉 演示完成!")
    print("💡 提示: 可以通过修改 DocumentConfig 来定制解析行为")
    print("📖 详细文档请参考: 文档解析优化完整讲义.md")
